#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<iostream>
#include<unordered_map>
using namespace std;
#define COMMAND_SIZE 1024
#define FORMAT "[%s@%s %s]@ "

#define MAX_ENVS 100
char *g_env[MAX_ENVS];
int g_envs=0;

#define MAXARGC 128
char *g_argv[MAXARGC];
int g_argc=0;

unordered_map<string,string>alias_list;

char cwd[1024];
char cwdenv[1024];
int lastcode=0;
void printargv()
{
  for(int i=0;i<g_argc;i++)
  {

    cout<<i<<":"<<g_argv[i]<<endl;
  }

}
const char *GetUserName()
{
  const char*name=getenv("USER");
  return name == NULL?"None":name;
}
const char* GetHostName()
{
  const char *hostname=getenv("HOSTNAME");
  return hostname == NULL ? "None" : hostname;
}
const char* GetPwd()
{
  const char* pwd=getenv("PWD");
  return pwd == NULL ? "None" : pwd;
}
const char* GetHome()
{
  const char*home=getenv("HOME");
  return home == NULL?"":home;
}
void InitEnv()
{
  extern char**environ;
  memset(g_env,0,sizeof(g_env));
  g_envs = 0;
  for(int i = 0; environ[i]; i++)
  {
    g_env[i]=(char*)malloc(strlen(environ[i])+1);
    strcpy(g_env[i],environ[i]);
    g_envs++;
  }
  g_env[g_envs++]=(char*)"HAHA=for_test";
  g_env[g_envs]=NULL;
  for(int i=0;g_env[i];i++)
  {
    putenv(g_env[i]);
  }
  environ=g_env;
}
string frontwhere;
bool Cd()
{
  const char* oldPwd=GetPwd();
  if(g_argc == 1)
  {
    string home = GetHome();
    if(home.empty())
    {
      return true;
    }
    chdir(home.c_str());
  }
  else
  {
    string where = g_argv[1];
    if(where == "-")
    {
      chdir(frontwhere.c_str());
    }
    else if(where == "~")
    {
      frontwhere=oldPwd;
      chdir(GetHome());
    }
    else
    {
      frontwhere = oldPwd;
      chdir(where.c_str());
    }
  }
  char newPwd[1024];
  if(getcwd(newPwd,sizeof(newPwd))!=nullptr)
  {
    setenv("PWD",newPwd,1);
  }
  return true;
}
void Echo()
{
  if(g_argc==2)
  {
    string opt=g_argv[1];
    if(opt == "$?")
    {
      cout<<"lastcode"<<endl;
      lastcode=0;
    }
    else if(opt[0]=='$')
    {
      string env_name=opt.substr(1);
      const char* env_value=getenv(env_name.c_str());
      if(env_value)
      {
        cout<<env_value<<endl;
      }
    }
    else
    {
      cout<<opt<<endl;
    }
  }
}
const char* DieName(const char* pwd);
void MakeCommandLine(char cmd_prompt[],int size)
{
  printf("%s",GetPwd());
  snprintf(cmd_prompt,size,FORMAT,GetUserName(),GetHostName(),DieName(GetPwd()));
}
void PrintCommandPrompt()
{
  char prompt[COMMAND_SIZE];                                      
  MakeCommandLine(prompt,sizeof(prompt));                         
	printf("%s",prompt);           
  fflush(stdout);
}
bool GetCommandline(char* out,int size)
{
  char*c=fgets(out,size,stdin);
  if(c == NULL)
  {
    return false;
  }
  else{
    c[strlen(c)-1]=0;
  }
  if(strlen(c) == 0)
  {
    return false;
  }
  return true;
}
const char* DieName(const char* pwd)
{
  for(int i=strlen(pwd)-1;i>=0;i--)
  {
    if(pwd[i]=='/')
    {
      return pwd+i+1;
    }
  }
  return "BUG";
}
bool CommandParse(char* Commandline)
{
  #define SEP " "
  g_argc = 0;
  g_argv[g_argc++] = strtok(Commandline,SEP);
  while((bool)(g_argv[g_argc++]=strtok(nullptr,SEP)));
  g_argc--;
  return true;
}
bool CheckAndExecBuiltin()
{
  string cmd=g_argv[0];
  if(cmd == "cd")
  {
    Cd();
    return true;
  }
  else if(cmd == "echo")
  {
    Echo();
    return true;
  }
  else if(cmd == "export")
  {

  }
  else if(cmd == "alias")
  {

  }
  return false;
}
int Execute()
{
  pid_t id=fork();
  if(id==0)
  {
    execvp(g_argv[0],g_argv);
    exit(1);
  }
  waitpid(id,nullptr,0);
  return 0;
}
int main()
{
  InitEnv();
  while(true)
  {
    PrintCommandPrompt();
    char Commandline[COMMAND_SIZE];
    if(!GetCommandline(Commandline,sizeof(Commandline)))
    {
      continue;
    }
    if(!CommandParse(Commandline))
    {
      continue;
    }
    if(CheckAndExecBuiltin())
    {
      continue;
    }
    Execute();
  }
  return 0;
}
